home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MacWorld 1999 July
/
Macworld (1999-07).dmg
/
Shareware World
/
Info
/
For Developers
/
Mops 3.4.sea
/
Mops source
/
Toolbox classes
/
AppleEvents
< prev
next >
Wrap
Text File
|
1997-09-29
|
8KB
|
280 lines
\ 10Dec93 DBH initial version
\ 12Feb94 DBH added proper disposal of AppleEvent and Reply via AEDisposeDesc at each and
\ every time we send an AppleEvent. Before, this was causing memory to be consumed and never
\ freed at each send.
\ It is interesting that, with this scheme at least, it is
\ not necessary to create and dispose the description record QEdesc at each send.
\ See general comments at the end of this file.
\ This AppleEvent class is at the moment geared to sending AEs to
\ Quick Edit. But it wouldn't be too hard to make it more general.
syscall AECreateDesc
syscall AEDisposeDesc
syscall AESend
syscall AECreateAppleEvent
:class AEDesc super{ object }
68k_record
{ longword descriptorType
handle dataHandle \ first 4 bytes of handle will = MSET after new:
var dataPtr
}
:m classinit:
'type MSET put: dataPtr \ put QE creator signature in a dataPtr
;m
:m new:
'type sign \ typeApplSignature
addr: dataPtr
8 \ dataSize
^base \ VAR result -> our record
AECreateDesc
IF ." failed to create AE Desc record" THEN
;m
:m release:
^base \ VAR theAEDesc -> our record
AEDisposeDesc \ here we actually use AEDisposeDesc to dispose an AEDesc
IF ." failed to dispose AE Desc record" THEN
;m
;class
AEDesc QEdesc
variable dummyReply 16 allot
:class AppleEvent super{ object }
68k_record
{ int what
var mclass
var when
var mID
int modifiers
var theClass \ will be 'type OPEN or TEXT for now. Could be other things later.
}
\ :m classinit: \ 12Feb94 DBH necessary??? apparently not
\ konst kHighLevelEvent put: what ;m
\ Guess what? We have to dispose of our AppleEvent AFTER EACH SEND !
\ and we must use AEDisposeDesc. This was not immediately obvious to me from IM.
\ Also, we must dispose of our reply, again using AEDisposeDesc. AEDisposeDesc seems to be
\ the universal dispoz-all for AE things. The penalty for not doing this is lost heap at every
\ send.
:m release: \ 12Feb94 DBH
^base AEDisposeDesc
IF ." failed to dispose of AppleEvent" THEN
dummyReply AEDisposeDesc
IF ." failed to dispose of Reply" THEN
;m
:m new: { theClass theID -- } \ theID MUST be a handle
theClass
theID
QEdesc \ we are always using this target here
konst kAutoGenerateReturnID
0 \ konst AnyTransactionID \ no call?
^base \ VAR result will be our own ivar record , but only using ivars
\ through modifiers
AECreateAppleEvent
IF " failed to create AppleEvent" cr THEN ;m
\ :m set: ( AEEventClass -- ) \ 12Feb94 DBH incorporated into new:
\ put: theClass ;m
:m send: ( -- oserr )
^base \ we are sending ourself, of course
dummyReply
konst kAEWaitReply \ sendmode, we must wait for reply so we don't
\ clobber the handle
\ before QE has a chance to deal with it.
konst kAENormalPriority \ sendPriority
konst kAEDefaultTimeout \ timeoutinticks see IM-VI 6-94
0 \ idleproc
0 \ filterproc
AESend
;m
;class
:class QEopen super{ object }
record
{ byte fileNameLength
32 bytes fileName
int volRef#
var dirID
var selStart
var SelEnd
}
:m put: { ^obj n1 n2 -- } \ file object and desired selection range
getname: [ ^obj ] ( addr len )
32 min dup put: fileNameLength addr: fileName swap cmove \ ala ctl example
getvref: [ ^obj ] put: volRef#
getdirID: [ ^obj ] put: dirID
n1 put: selStart
n2 put: SelEnd ;m
:m length: ( -- n ) \ can't send this message to an ivar!!
48 ;m
;class
\ This class will be used as our sole communication device to QE when sending AEs.
PPC?
[IF]
:class QE super{ object }
AppleEvent QEevent
QEopen tQEopen
string QEstr
[ELSE]
:class QE super{ object }
AppleEvent QEevent
QEopen tQEopen
string+ QEstr
[THEN]
:m new:
new: QEstr
new: QEdesc \ note that QEdesc is a public object
;m
:m release:
release: QEstr
release: QEdesc
;m
:m send: ( theClass -- oserr ) \ 12Feb94 DBH must new: and release: for each send!!
handle: QEstr ( ID ) new: QEevent \ always using QEstr handle as our ID.
send: QEevent
clear: QEstr \ 12Feb94 DBH must always clear the string because next action
\ may be to simply add as when doing a text:
release: QEevent
;m
:m openFile: ( ^obj n1 n2 -- oserr ) \ file object and selection range
put: tQEopen
addr: tQEopen length: tQEopen put: QEstr
'type OPEN send: self ;m
:m text: ( addr len -- ) \ text to be "typed" into front QE window
\ if no window open in QE, no action from QE, just a beep
\ put: QEstr \ 27Jan94 DBH
\ 'type TEXT send: self ;m
add: QEstr ;m
variable emitvar 4 allot
:m cr: ( -- oserr )
13 emitvar c!
emitvar 1 text: self
'type TEXT send: self
clear: QEstr ;m
:m newWindow: ( addr len -- oserr ) \ opens a new window in QE, does not create a file on disk
\ if no more available windows in QE, no action, just a beep
put: QEstr
'type NEWF send: self ;m
:m putRect: ( l t r b -- oserr ) \ will set the front QE window portrect to these values
\ if no window open in QE, no action from QE, just a beep
put: temprect
addr: temprect 8 put: QEstr
'type RECT send: self ;m
:m find: ( addr len -- oserr ) \ will request that QE find first occurrence of
\ the given text in the front qe window. We are limited to strings of length
\ 255 and less. All searches will be case insensitive.
put: QEstr
>uc: QEstr \ QE needs all upper case for this
'type FIND send: self ;m
;class
QE tQE \ we now have just one object for sending commands to Quick Edit
: inittQE
instld? ?EXIT \ Mustn't do this in installed apps
[ ppc? not ]
[if]
AppleEvents? 0EXIT
[then]
new: tQE ;
inittQE
' inittQE add: init_actions
endload
+echo
file testfile
: GO1
'type TEXT 1 stdget: testfile . cr
testfile 10 20 openFile: tQE . ;
: GO2
" Hello World" text: tQE cr: tQE . ; \ note how we must always end with a cr: to send:
: GO3
" My File Name" newwindow: tQE . ;
: GO4
100 50 300 350 putrect: tQE . ;
endload
****** GENERAL COMMENTS *******
It is very important to understand the "trick" being used here for communication between Mops and
QE. We follow Apple's recipe for everything except for the descriptor record scheme. Instead of
building and then deciphering the seemingly overly complex descriptor records for each AE, it seemed
to me to be much more straightforward to just send a handle to whatever data structure we wish.
Since we control everything at both ends (Mops and QE), then why go through all of the gyrations of
the AEdesc record handling? We avoid having to deal with any of the AEPutParam/AEGetParam etc.
Also, we don't even have to deal with AEInstallEventHandler or AEProcessAppleEvent!
What we do is to only define our AppleEvents by class and not by also providing an ID. This does
not seem to be much of a limitation on defining AEs since there are certainly plenty of different
classes we could define with the 32 bit class identifier. Most importantly, we have now freed up
the ID of our AE for use in any way that we wish, and we wish to make our ID the handle to the data
we want to pass from Mops to QE or vice versa. I don't know what kind of problems this could cause.
To date, I have noticed no problems. But this does not seem to be the way Apple intended. So
beware. Note that both Mops and QE accomplish AE communication in exactly the same (non-standard)
way.
The memory problem that both QE 2.4 and the original Mops 2.4 release suffered was not related
to this scheme. That problem existed due to the lack of understanding on my part of the need for
disposing AppleEvents and AE Replies after each AESend. But note that we do not need to create
and dispose our descriptor record itself. But we must use AEDisposeDesc to dispose of the
AppleEvent and AEReply ( no AEDisposeAppleEvent exists, apparently).
-Doug Hoffman \ 12Feb94